/** @file

  Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef __SYNQUACER_I2C_DXE_H__
#define __SYNQUACER_I2C_DXE_H__

#include <PiDxe.h>

#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeLib.h>

#include <Protocol/I2cMaster.h>
#include <Protocol/NonDiscoverableDevice.h>

extern EFI_COMPONENT_NAME2_PROTOCOL gSynQuacerI2cDriverComponentName2;
extern EFI_DRIVER_BINDING_PROTOCOL  gSynQuacerI2cDriverBinding;

#define SYNQUACER_I2C_SIGNATURE         SIGNATURE_32 ('S', 'I', '2', 'C')
#define SYNQUACER_I2C_FROM_THIS(a)      CR ((a), SYNQUACER_I2C_MASTER, \
                                            I2cMaster, SYNQUACER_I2C_SIGNATURE)

#pragma pack(1)
typedef struct {
  VENDOR_DEVICE_PATH              Vendor;
  UINT64                          MmioBase;
  EFI_DEVICE_PATH_PROTOCOL        End;
} SYNQUACER_I2C_DEVICE_PATH;
#pragma pack()

typedef struct {
  UINT32                          Signature;
  EFI_I2C_MASTER_PROTOCOL         I2cMaster;
  EFI_PHYSICAL_ADDRESS            MmioBase;
  SYNQUACER_I2C_DEVICE_PATH       DevicePath;
  NON_DISCOVERABLE_DEVICE         *Dev;
  EFI_EVENT                       VirtualAddressChangeEvent;
  BOOLEAN                         Runtime;
} SYNQUACER_I2C_MASTER;

EFI_STATUS
SynQuacerI2cInit (
  IN      EFI_HANDLE              DriverBindingHandle,
  IN      EFI_HANDLE              ControllerHandle
  );

EFI_STATUS
SynQuacerI2cRelease (
  IN      EFI_HANDLE              DriverBindingHandle,
  IN      EFI_HANDLE              ControllerHandle
  );

#define REFCLK_RATE         FixedPcdGet32 (PcdI2cReferenceClock)

#define DIV_ROUND_UP(n, d)  (((n) + (d) - 1) / (d))

#define F_I2C_SPEED_SM      100000
#define F_I2C_SPEED_FM      400000

// I2C register adress definitions
#define F_I2C_REG_BSR       (0x00 << 2) // Bus Status Regster
#define F_I2C_REG_BCR       (0x01 << 2) // Bus Control Register
#define F_I2C_REG_CCR       (0x02 << 2) // Clock Control Register
#define F_I2C_REG_ADR       (0x03 << 2) // Address Register
#define F_I2C_REG_DAR       (0x04 << 2) // Data Register
#define F_I2C_REG_CSR       (0x05 << 2) // Expansion CS Register
#define F_I2C_REG_FSR       (0x06 << 2) // Bus Clock Frequency Register
#define F_I2C_REG_BC2R      (0x07 << 2) // Bus Control 2 Register

// I2C register bit definitions
#define F_I2C_BSR_FBT       BIT0        // First Byte Transfer
#define F_I2C_BSR_GCA       BIT1        // General Call Address
#define F_I2C_BSR_AAS       BIT2        // Address as Slave
#define F_I2C_BSR_TRX       BIT3        // Transfer/Receive
#define F_I2C_BSR_LRB       BIT4        // Last Received Bit
#define F_I2C_BSR_AL        BIT5        // Arbitration Lost
#define F_I2C_BSR_RSC       BIT6        // Repeated Start Condition
#define F_I2C_BSR_BB        BIT7        // Bus Busy

#define F_I2C_BCR_INT       BIT0        // Interrupt
#define F_I2C_BCR_INTE      BIT1        // Interrupt Enable
#define F_I2C_BCR_GCAA      BIT2        // General Call Access Acknowledge
#define F_I2C_BCR_ACK       BIT3        // Acknowledge
#define F_I2C_BCR_MSS       BIT4        // Master Slave Select
#define F_I2C_BCR_SCC       BIT5        // Start Condition Continue
#define F_I2C_BCR_BEIE      BIT6        // Bus Error Interrupt Enable
#define F_I2C_BCR_BER       BIT7        // Bus Error

#define F_I2C_CCR_CS_MASK   0x1f        // CCR Clock Period Select
#define F_I2C_CCR_EN        BIT5        // Enable
#define F_I2C_CCR_FM        BIT6        // Speed Mode Select

#define F_I2C_CSR_CS_MASK   0x3f        // CSR Clock Period Select

#define F_I2C_BC2R_SCLL     BIT0        // SCL Low Drive
#define F_I2C_BC2R_SDAL     BIT1        // SDA Low Drive
#define F_I2C_BC2R_SCLS     BIT4        // SCL Status
#define F_I2C_BC2R_SDAS     BIT5        // SDA Status

// PCLK frequency
#define F_I2C_BUS_CLK_FR(rate)          ((rate) / 20000000 + 1)

#define F_I2C_MIN_CLK_RATE              (14 * 1000000)  // min frequency 14 MHz
#define F_I2C_MAX_CLK_RATE              (200 * 1000000) // max frequency 200 MHz
#define F_I2C_CLK_RATE_18M              (18 * 1000000)  // threshold freq 18 MHz

// STANDARD MODE frequency
#define F_I2C_CLK_MASTER_STANDARD(rate) \
            DIV_ROUND_UP (DIV_ROUND_UP ((rate), 100000) - 2, 2)

// FAST MODE frequency
#define F_I2C_CLK_MASTER_FAST(rate) \
            DIV_ROUND_UP ((DIV_ROUND_UP ((rate), 400000) - 2) * 2, 3)

// (clkrate <= 18000000)
// calculate the value of CS bits in CCR register in standard mode
#define F_I2C_CCR_CS_STANDARD_MAX_18M(rate) \
            ((F_I2C_CLK_MASTER_STANDARD (rate) - 65) & F_I2C_CCR_CS_MASK)

// calculate the value of CS bits in CSR register in standard mode
#define F_I2C_CSR_CS_STANDARD_MAX_18M(rate) 0x00

// calculate the value of CS bits in CCR register in fast mode
#define F_I2C_CCR_CS_FAST_MAX_18M(rate) \
            ((F_I2C_CLK_MASTER_FAST (rate) - 1)  & F_I2C_CCR_CS_MASK)

// calculate the value of CS bits in CSR register in fast mode
#define F_I2C_CSR_CS_FAST_MAX_18M(rate) 0x00

// (clkrate > 18000000)
// calculate the value of CS bits in CCR register in standard mode */
#define F_I2C_CCR_CS_STANDARD_MIN_18M(rate) \
            ((F_I2C_CLK_MASTER_STANDARD (rate) - 1) & F_I2C_CCR_CS_MASK)

// calculate the value of CS bits in CSR register in standard mode
#define F_I2C_CSR_CS_STANDARD_MIN_18M(rate) \
            (((F_I2C_CLK_MASTER_STANDARD (rate) - 1) >> 5) & F_I2C_CSR_CS_MASK)

// calculate the value of CS bits in CCR register in fast mode
#define F_I2C_CCR_CS_FAST_MIN_18M(rate) \
            ((F_I2C_CLK_MASTER_FAST (rate) - 1) & F_I2C_CCR_CS_MASK)

/* calculate the value of CS bits in CSR register in fast mode */
#define F_I2C_CSR_CS_FAST_MIN_18M(rate) \
            (((F_I2C_CLK_MASTER_FAST (rate) - 1) >> 5) & F_I2C_CSR_CS_MASK)

#endif
